//Copyright (C) 2005  Neale Clark
//
//This program is free software; you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation; either version 2 of the License, or
//(at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

package tat;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

import javax.swing.JOptionPane;

import tat.domain.DomainModelRelation;
import tat.domain.Requirement;
import tat.domain.TatActor;
import tat.domain.TatAttribute;
import tat.domain.TatClass;
import tat.domain.TatUseCase;
import tat.domain.UseCaseRelation;
import tat.exception.ObjectAlreadyExistsException;
import tat.mvc.TATController;
import tat.mvc.TATFrame;
import tat.mvc.TextFrame;

//This class is serialisable to enable storing of a partially complete model

/**
 * This is the model for the application, all processing is carried out here.
 */
public class TATAppLegacyWrapper implements Serializable {

	private TatApp controle;

	private java.io.File sor; // Holds reference to file used
	private TATController mvcController; // Holds reference to controller

	public TATAppLegacyWrapper(final TATController cont) {
		this.mvcController = cont;
		controle = new TatAppImpl();
	}

	public void resetApplication() {
		controle.resetApplication();
	}

	private void readObject(final ObjectInputStream ois)
			throws ClassNotFoundException, IOException {
		ois.defaultReadObject();
	}

	private void writeObject(final ObjectOutputStream oos) throws IOException {
		oos.defaultWriteObject();
	}

	// Getters and setters

	public java.io.File getSor() {
		return sor;
	}

	public void setSor(final java.io.File sor) {
		this.sor = sor;
	}

	public TATController getCont() {
		return mvcController;
	}

	public void setCont(final TATController cont) {
		this.mvcController = cont;
	}

//	public java.util.HashMap getUseCases() {
//		return useCases;
//	}

//	public void setUseCases(java.util.HashMap useCases) {
//		this.useCases = useCases;
//	}

//	public java.util.Set getUcKs() {
//		return ucKs;
//	}

//	public void setUcKs(java.util.Set ucKs) {
//		this.ucKs = ucKs;
//	}

//	public java.util.HashMap getClasses() {
//		return classes;
//	}
//
//	public void setClasses(java.util.HashMap classes) {
//		this.classes = classes;
//	}

//	public java.util.Set getClKs() {
//		return clKs;
//	}
//
//	public void setClKs(java.util.Set clKs) {
//		this.clKs = clKs;
//	}
//
//	public java.util.Set getAttKs() {
//		return attKs;
//	}
//
//	public void setAttKs(java.util.Set attKs) {
//		this.attKs = attKs;
//	}

	// Method to read the data file sor and return a String for display
	// Ensure a call to setSor() before calling

	public String readFile() {
		try {
			FileReader in = new FileReader(sor);
			StringBuffer text = new StringBuffer("");
			text.ensureCapacity(500);
			int c;

			while ((c = in.read()) != -1) {
				text.append((char) c);

			}
			in.close();

			return text.toString();
		} catch (FileNotFoundException fnf) {
			return "File could not be found";
		} catch (IOException io) {
			return "Error reading file";
		}
	}

	// Method to save text file

	public void saveTxt(final File file) {
		try {
			FileWriter out = new FileWriter(file);
			String text = this.toString();
			out.write(text);
			out.flush();
			out.close();
		} catch (IOException io) {
		}
	}

	// Method to XML file

	public void saveXML(final File file) {
		try {
			FileWriter out = new FileWriter(file);
			String text = this.toXML();
			out.write(text);
			out.flush();
			out.close();

		} catch (IOException io) {
		}
	}

	public void saveRequirementsReport(final File file) {
		try {
			FileWriter out = new FileWriter(file);
			String text = this.obterRequirementsReport();
			out.write(text);
			out.flush();
			out.close();

		} catch (IOException io) {
		}
	}

	// Method to create a new Actor or report already exists

	public void createActor(final String name) {
		controle.createActor(name);
		updateActorKs();
	}

	// Method to create new use case or report already exists

	public void createUseCase(final String name) {
		try {
			controle.createUseCase(name);
			updateUseCaseKs();
		} catch (ObjectAlreadyExistsException e) {
			TATFrame f = mvcController.getGui();
			JOptionPane.showMessageDialog(f, name + " already exists!",
					"Use Case Exists", JOptionPane.WARNING_MESSAGE);
		}
	}

	// Method to create new class or report already exists

	public void createClass(final String name) {
		try {
			controle.createClass(name);
			updateClassKs();
		} catch (ObjectAlreadyExistsException e) {
			TATFrame f = mvcController.getGui();
			JOptionPane.showMessageDialog(f, name + " already exists!",
					"Class Exists", JOptionPane.WARNING_MESSAGE);
		}
	}

	// Method to create new attribute for selected class

	public void createAttribute(final String cla, final String name) {
		if (cla != null) {
			try {
				controle.createAttribute(cla, name);
				updateAttKs(cla);
			} catch (ObjectAlreadyExistsException e) {
				TATFrame f = mvcController.getGui();
				JOptionPane.showMessageDialog(f, name + " already exists!",
						"Attribute Exists", JOptionPane.WARNING_MESSAGE);
			}
//			TATClass c = (TATClass) classes.get(cla);
//			if (c.getAttributes().containsKey(name)) {
//				TATFrame f = mvcController.getGui();
//				JOptionPane.showMessageDialog(f, name + " already exists!",
//						"Attribute Exists", JOptionPane.WARNING_MESSAGE);
//			} else {
//				c.getAttributes().put(name, new TATAtt(name));
//				updateAttKs(c);
//			}
		} else {
			TATFrame f = mvcController.getGui();
			JOptionPane.showMessageDialog(f, "Please select a Class first!",
					"Select a Class", JOptionPane.WARNING_MESSAGE);
		}
	}

	public void createTextRequirement(final String valor, final int position) {

		controle.createRequirement(valor, position);
		updateRequirementKs();

	}

	public void createUcRequirement(final String valor) {

		controle.createUcRequirement(valor);
		updateRequirementKs();

	}

	public void createDomRequirement(final String valor) {

		controle.createDomRequirement(valor);
		updateRequirementKs();

	}

	public void createRelationRequirement(final String valor) {

		controle.createRelationRequirement(valor);
		updateRequirementKs();

	}

	// Methods to delete Actors, Use Cases, Classes and Attributes

	public void deleteActor(final String name) {
		TATFrame f = mvcController.getGui();
		int retVal = JOptionPane.showConfirmDialog(f,
				"Do you really want to delete " + name + "!", "Delete Actor",
				JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
		if (retVal == JOptionPane.YES_OPTION) {
			controle.removeActor(name);
			updateActorKs();
			updateUCActorKs();
			updateRequirementKs();
		}
	}

	public void deleteUseCase(final String name) {
		TATFrame f = mvcController.getGui();
		int retVal = JOptionPane.showConfirmDialog(f,
				"Do you really want to delete " + name + "!",
				"Delete Use Case", JOptionPane.YES_NO_OPTION,
				JOptionPane.QUESTION_MESSAGE);
		if (retVal == JOptionPane.YES_OPTION) {
			controle.removeUseCase(name);
			updateUseCaseKs();
			updateUCActorKs();
			updateRequirementKs();
		}
	}

	public void deleteClass(final String name) {
		TATFrame f = mvcController.getGui();
		int retVal = JOptionPane.showConfirmDialog(f,
				"Do you really want to delete " + name + "!", "Delete Class",
				JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
		if (retVal == JOptionPane.YES_OPTION) {
			controle.removeClass(name);
			updateClassRelationKs();
			updateRequirementKs();
			updateClassKs();
			updateAttKs(null);
		}
	}

	public void deleteAttribute(final String cla, final String name) {
		TATFrame f = mvcController.getGui();
		int retVal = JOptionPane.showConfirmDialog(f,
				"Do you really want to delete " + name + "!",
				"Delete Attribute", JOptionPane.YES_NO_OPTION,
				JOptionPane.QUESTION_MESSAGE);
		if (retVal == JOptionPane.YES_OPTION) {
			controle.removeAttribute(cla, name);
			updateAttKs(cla);
		}
	}

	public void deleteUCActorRelation(final String relationName){
		TATFrame f = mvcController.getGui();
		int retVal = JOptionPane.showConfirmDialog(f,
				"Do you really want to delete " + relationName + "!",
				"Delete UseCase-Model Relation", JOptionPane.YES_NO_OPTION,
				JOptionPane.QUESTION_MESSAGE);
		if (retVal == JOptionPane.YES_OPTION) {
			controle.removeUCActorRelation(relationName);
			updateUCActorKs();
			updateRequirementKs();
		}
	}


	public void deleteDomainModelRelation(final String relationName){
		TATFrame f = mvcController.getGui();
		int retVal = JOptionPane.showConfirmDialog(f,
				"Do you really want to delete " + relationName + "!",
				"Delete Domain-Model Relation", JOptionPane.YES_NO_OPTION,
				JOptionPane.QUESTION_MESSAGE);
		if (retVal == JOptionPane.YES_OPTION) {
			controle.removeDomainModelRelation(relationName);
			updateClassRelationKs();
			updateRequirementKs();
		}
	}

	public void deleteRequirement(final String name) {
		TATFrame f = mvcController.getGui();
		int retVal = JOptionPane.showConfirmDialog(f,
				"Do you really want to delete " + name + "!",
				"Delete Requirement", JOptionPane.YES_NO_OPTION,
				JOptionPane.QUESTION_MESSAGE);
		if (retVal == JOptionPane.YES_OPTION) {
			controle.removeRequirement(name);
			updateRequirementKs();
		}
	}

	// Methods to EDIT Actors, Use Cases, Classes and Attributes

	public void editActor(final String name) {
		TATFrame f = mvcController.getGui();
		String oldActor = name;
		String retVal = (String) JOptionPane.showInputDialog(f,
				"Enter update for " + name, "Edit Actor",
				JOptionPane.PLAIN_MESSAGE, null, null, name);
		if (retVal != null && ! retVal.equals("")) {
			controle.editActor(oldActor, retVal);
			updateActorKs();
			updateUCActorKs();
		}
	}

	public void editUseCase(final String name) {
		TATFrame f = mvcController.getGui();
		String oldUseCase = name;
		String retVal = (String) JOptionPane.showInputDialog(f,
				"Enter update for " + name, "Edit Use Case",
				JOptionPane.PLAIN_MESSAGE, null, null, name);
		if (retVal != null && ! retVal.equals("")) {
			controle.editUseCase(oldUseCase, retVal);
			updateUseCaseKs();
			updateUCActorKs();
		}
	}

	public void editClass(final String name) {
		TATFrame f = mvcController.getGui();
		String oldClassValue = name;
		String newClassValue = (String) JOptionPane.showInputDialog(f,
				"Enter update for " + name, "Edit Class",
				JOptionPane.PLAIN_MESSAGE, null, null, name);
		if (newClassValue != null && ! newClassValue.equals("")) {
			controle.editClass(oldClassValue, newClassValue);
			updateClassKs();
			updateClassRelationKs();
			updateRequirementKs();
		}
	}

	public void editAttribute(final String cla, final String name) {
		TATFrame f = mvcController.getGui();
		String oldAttribute = name;
		String newAttributeName = (String) JOptionPane.showInputDialog(f,
				"Enter update for " + name, "Edit Attribute",
				JOptionPane.PLAIN_MESSAGE, null, null, name);

		if (newAttributeName != null && !newAttributeName.equals("")) {
			controle.editAttribute(cla, oldAttribute, newAttributeName);
			updateAttKs(cla);
		}
	}

	public void editRequirement(final String name) {
		TATFrame f = mvcController.getGui();
		String oldReqValue = name;
		String newReqValue = (String) JOptionPane.showInputDialog(f,
				"Enter update for " + name, "Edit Requirement",
				JOptionPane.PLAIN_MESSAGE, null, null, name);
		if (newReqValue != null && ! newReqValue.equals("")) {
			controle.editRequirement(oldReqValue, newReqValue);
			this.updateRequirementKs();
		}
	}

	// Method to create a String representation of Model

	@Override
	public String toString() {
		return controle.showModelAsText();
	}

	public String toXML() {
		return controle.showModelAsXML();
	}

	// Helper methods to show Model types improve for final or delete

	public void showText() {
		TATFrame f = mvcController.getGui();
		TextFrame tf = new TextFrame(this.toString());
		tf.pack();
		tf.show();
	}

	public void showXML() {
		TATFrame f = mvcController.getGui();
		TextFrame tf = new TextFrame(this.toXML());
		tf.pack();
		tf.show();

	}

	public void showRequirementsReport(){
		TATFrame f = mvcController.getGui();
		TextFrame tf = new TextFrame(this.obterRequirementsReport());
		tf.pack();
		tf.show();
	}

	public String obterRequirementsReport(){
		 return controle.showRequirementsReport();
	}

	// Method to display attributes of selected class

	public void getClassAtts(final String cl) {
//		TATClass c = (TATClass) classes.get(cl);
//		if (c != null) {
//			attKs = c.getAttSet();
//			Iterator it = getAttKs().iterator();
//			mvcController.getAttLm().clear();
//			while (it.hasNext()) {
//				mvcController.getAttLm().addElement(it.next());
//			}
//		} else {
//			mvcController.getAttLm().clear();
//		}
	}

	// Helper methods to update KeySets

	void updateActorKs() {
		TatActor[] actors = controle.conferActors();
		mvcController.getActLm().clear();
		for (TatActor actor : actors) {
			mvcController.getActLm().addElement(actor.name());
		}
	}

	void updateUseCaseKs() {
		TatUseCase[] useCases = controle.conferUseCases();

		mvcController.getUcLm().clear();
		for (TatUseCase uc : useCases) {
			mvcController.getUcLm().addElement(uc.name());
		}
	}

	void updateClassKs() {
		TatClass[] classes = controle.conferClasses();

		mvcController.getClassLm().clear();

		for (TatClass c : classes) {
			mvcController.getClassLm().addElement(c.name());
		}
	}

	void updateAttKs(final String className) { // c == null means class has been deleted
		TatClass[] conferClasses = controle.conferClasses();

		TatClass classToUpdate = null;

		for (TatClass c : conferClasses) {
			if (c.name().equals(className)) {
				classToUpdate = c;
			}
		}

		mvcController.getAttLm().clear();
		if (classToUpdate != null) {

			for (TatAttribute att : classToUpdate.attributes()) {
				mvcController.getAttLm().addElement(att.name());
			}
		}

	}

	void updateRequirementKs() {
		Requirement[] reqs = controle.conferRequirements();
		mvcController.getReqLm().clear();
		for (Requirement req : reqs) {
			mvcController.getReqLm().addElement(req.value());
		}
	}

	void updateClassRelationKs() {
		DomainModelRelation[] relations = controle.conferDomainModelRelations();

		mvcController.getClassRelLm().clear();
		for (DomainModelRelation r : relations) {
			mvcController.getClassRelLm().addElement(r.name());
		}
	}

	public void createClassRelation(final String origin, final String destination,
			final String originMultiplicity, final String destinationMultiplicity,
			final String type, final boolean navigable, final boolean createRequirement) {
		controle.createClassRelation(origin, destination, originMultiplicity, destinationMultiplicity, navigable, type, createRequirement);
		updateClassRelationKs();
	}

	 public void createUCActorRelation(final String actorName, final String ucName) {
		controle.createUCActorRelation(actorName, ucName);
		updateUCActorKs();
	}

	public void updateUCActorKs() {
		UseCaseRelation[] relations = controle.conferUCActorRelations();
		mvcController.getUCActorRelLm().clear();
		for (UseCaseRelation r : relations) {
			mvcController.getUCActorRelLm().addElement(r.name());
		}
	}
}
